<template>
  <div class="binding-panel">
    <!-- <h3>字段与单元格绑定面板</h3>    -->
    <div class="form-section">
      <label>字段名：</label>
      <input v-model="singlePath" placeholder="如 Name" />
      <label>单元格：</label>
      <input v-model="singleRange" placeholder="如 A1或单击单元格获取" />
      <button @click="addSingleBinding">添加绑定</button>
    </div>

    <div class="form-section">
      <label>批量绑定（JSON）</label>
      <textarea v-model="batchJson" rows="4" placeholder='{"name":"A1","age":"B1"}'></textarea>
      <button @click="addBatchBinding">批量添加</button>
    </div>

    <!-- 当前绑定列表 -->
    <div class="bindings">
      <h4>当前绑定：</h4>
      <table>
        <thead>
          <tr>
            <th>字段名称</th>
            <th>单元格范围</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(_, path) in bindings" :key="path">
            <!-- 数据路径 -->
            <td>
              <input v-if="editing?.oldPath === path" v-model="editing.path" style="width: 50%" />
              <span v-else>{{ path }}</span>
            </td>

            <!-- 单元格范围 -->
            <td>
              <input v-if="editing?.oldPath === path" v-model="editing.range" style="width: 50%" />
              <span v-else>{{ bindings[path] }}</span>
            </td>

            <!-- 操作按钮 -->
            <td>
              <!-- 编辑中 -->
              <template v-if="editing?.oldPath === path">
                <button @click="saveEdit">保存</button>
                <button @click="cancelEdit">取消</button>
              </template>

              <!-- 普通状态 -->
              <template v-else>
                <button @click="startEdit(path)">修改</button>
                <button @click="removeBinding(path)">删除</button>
              </template>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <!-- 数据源操作 -->
    <div class="form-section">
      <label>数据源 JSON：</label>
      <textarea v-model="dataSourceJson" rows="3" placeholder='{"name":"张三","age":18}'></textarea>
      <button @click="setDataSourceFromInput">设置数据源</button>
    </div>

    <div class="form-section">
      <label>当前数据源：</label>
      <button @click="getDataSourceToSpan">获取数据源</button>
      <pre v-if="currentDataSource">{{ currentDataSource }}</pre>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, defineProps } from "vue";
import type { CellValue, IDisposable } from "@univerjs/core";
import type { ISetRangeValuesMutationParams } from "@univerjs/sheets";
import {
  covertCellValue,
  covertCellValues,
  ICommandService,
  Injector,
  toDisposable,
  IUniverInstanceService,
  Workbook,
  UniverInstanceType,
} from "@univerjs/core";
import {
  deserializeRangeWithSheet as pr,
  serializeRange as sr,
} from "@univerjs/engine-formula";
import { filter } from "rxjs";
import {
  SetRangeValuesCommand,
  SetRangeValuesMutation,
  SheetsSelectionsService,
} from "@univerjs/sheets";
const props = defineProps<{
  injector: Injector;
}>();

const _univerInstanceService = props.injector.get(IUniverInstanceService);
const workbook = _univerInstanceService.getCurrentUnitOfType<Workbook>(
  UniverInstanceType.UNIVER_SHEET
)!;
const worksheet = workbook.getActiveSheet();
let bindings = reactive<Record<string, string>>({});
bindings = worksheet.getCustomMetadata()?.bindings || {};
const singlePath = ref("");
const singleRange = ref("");
const batchJson = ref("");
const editing = ref<{ path: string; oldPath: string; range: string } | null>(
  null
);
// 防止单元格值变化引起的循环更新
let IfsetSource = false;
// 更新单元格值
function _updateCellValue(dataPath: string, cell: string): void {
  const worksheet = workbook.getActiveSheet();
  const _data = worksheet.getCustomMetadata()?.dataSource;
  if (!_data) return;
  const _commandService = props.injector.get(ICommandService);
  const value = _getValueFromDataSource(dataPath, _data);
  if (value !== undefined && value !== null) {
    const { startRow, startColumn, endRow, endColumn } = pr(cell).range;
    const range = worksheet
      .getRange(startRow, startColumn, endRow, endColumn)
      .getRangeData();
    if (cell.includes(":") && Array.isArray(value)) {
      const realValue = covertCellValues(value as CellValue[][], range);
      _commandService.syncExecuteCommand(SetRangeValuesCommand.id, {
        unitId: worksheet.getUnitId(),
        subUnitId: worksheet.getSheetId(),
        range,
        value: realValue,
      });
    } else {
      const realValue = covertCellValue(value as CellValue);
      _commandService.syncExecuteCommand(SetRangeValuesCommand.id, {
        unitId: worksheet.getUnitId(),
        subUnitId: worksheet.getSheetId(),
        range,
        value: realValue,
      });
    }
  }
}

function _getValueFromDataSource(
  path: string,
  source: Record<string, unknown>
): unknown {
  return path.split(".").reduce<unknown>((obj, key) => {
    if (
      obj &&
      typeof obj === "object" &&
      key in (obj as Record<string, unknown>)
    ) {
      return (obj as Record<string, unknown>)[key];
    }
    return undefined;
  }, source);
}
// ...existing code...
// 设置绑定路径
function setBindingPath(dataPath: string, cell: string): void {
  const worksheet = workbook.getActiveSheet();
  const _customMetadata = worksheet.getCustomMetadata() || {};
  const _bindings = worksheet.getCustomMetadata()?.bindings || {};
  const _dataSource = worksheet.getCustomMetadata()?.dataSource || {};
  _bindings[dataPath] = cell;
  if (_customMetadata) {
    _customMetadata.bindings = { ..._customMetadata.bindings, ..._bindings };
    worksheet.setCustomMetadata(_customMetadata);
    if (!Object.hasOwn(_dataSource, dataPath)) {
      getDataSource();
    }
  }
  if (_dataSource) {
    _updateCellValue(dataPath, cell);
  }
}
// 设置绑定JSON
function setBinding(bindings: Record<string, string>): void {
  const worksheet = workbook.getActiveSheet();
  const _customMetadata = worksheet.getCustomMetadata() || {};
  let _bindings = worksheet.getCustomMetadata()?.bindings || {};
  const _dataSource = worksheet.getCustomMetadata()?.dataSource || {};
  _bindings = { ..._bindings, ...bindings };
  if (_customMetadata) {
    _customMetadata.bindings = _bindings;
    worksheet.setCustomMetadata(_customMetadata);
    getDataSource();
  }
  if (_dataSource) {
    for (const dataPath in _bindings) {
      if (Object.prototype.hasOwnProperty.call(_bindings, dataPath)) {
        const cell = _bindings[dataPath];
        _updateCellValue(dataPath, cell);
      }
    }
  }
}
// 设置绑定数据库数据源
// @ts-ignore
function setDataSource(
  source: Record<string, CellValue | CellValue[][]>
): void {
  const worksheet = workbook.getActiveSheet();
  const _customMetadata = worksheet.getCustomMetadata() || {};
  const _dataSource = source;
  const _bindings = worksheet.getCustomMetadata()?.bindings || {};
  if (_customMetadata) {
    _customMetadata.dataSource = {
      ..._customMetadata.dataSource,
      ..._dataSource,
    };
    worksheet.setCustomMetadata(_customMetadata);
    IfsetSource = true;
  }
  Object.keys(_bindings).forEach((dataPath) => {
    IfsetSource = true;
    const cell = _bindings[dataPath];
    _updateCellValue(dataPath, cell);
  });
}
// 获取页面数据源
function getDataSource(): Readonly<Record<string, unknown>> | null {
  const worksheet = workbook.getActiveSheet();
  const _bindings = worksheet.getCustomMetadata()?.bindings || {};
  const _dataSource = worksheet.getCustomMetadata()?.dataSource || {};
  if (_bindings) {
    for (const dataPath in _bindings) {
      if (
        Object.prototype.hasOwnProperty.call(_bindings, dataPath) &&
        !IfsetSource
      ) {
        const cell = _bindings[dataPath];
        const { startRow, startColumn, endRow, endColumn } = pr(cell).range;
        const range = worksheet.getRange(
          startRow,
          startColumn,
          endRow,
          endColumn
        );
        if (cell.includes(":")) {
          // 区域，读取二维数组
          _dataSource[dataPath] = range
            .getValues()
            .map((row: any) => row.map((cell: any) => cell?.v));
        } else {
          const cellValue = range.getValue()?.v;
          _dataSource[dataPath] = cellValue;
        }
      }
      IfsetSource = false;
    }
  }
  return _dataSource || {};
}
// 加载快照上的绑定和数据源
function loadBindings(): void {
  const worksheet = workbook.getActiveSheet();
  const _bindings = worksheet.getCustomMetadata()?.bindings || {};
  const _dataSource = worksheet.getCustomMetadata()?.dataSource || {};
  const commandService = props.injector.get(ICommandService);
  commandService.onCommandExecuted((command: any) => {
    if (command.id === SetRangeValuesMutation.id) {
      const _bindings = worksheet.getCustomMetadata()?.bindings || {};
      const _dataSource = worksheet.getCustomMetadata()?.dataSource || {};
      const params = command.params as ISetRangeValuesMutationParams;
      if (
        params.unitId === worksheet.getUnitId() &&
        params.subUnitId === worksheet.getSheetId() &&
        params.cellValue &&
        _bindings &&
        !IfsetSource
      ) {
        for (const dataPath in _bindings) {
          if (Object.prototype.hasOwnProperty.call(_bindings, dataPath)) {
            const cell = _bindings[dataPath];
            const { startRow, startColumn, endRow, endColumn } = pr(cell).range;
            const range = worksheet.getRange(
              startRow,
              startColumn,
              endRow,
              endColumn
            );
            if (cell.includes(":")) {
              _dataSource[dataPath] = range
                .getValues()
                .map((row: any) => row.map((cell: any) => cell?.v));
            } else {
              const cellValue = range.getValue()?.v;
              _dataSource[dataPath] = cellValue;
              // console.log(`[loadBindings] 更新单元格绑定:`, _dataSource);
            }
          }
        }
        IfsetSource = false;
      }
    }
  });
  if (_dataSource && _bindings) {
    Object.keys(_bindings).forEach((dataPath) => {
      const cell = _bindings[dataPath];
      _updateCellValue(dataPath, cell);
    });
  }
}

function removeBindingPath(dataPath: string): void {
  const worksheet = workbook.getActiveSheet();
  const _customMetadata = worksheet.getCustomMetadata() || {};
  const _bindings = worksheet.getCustomMetadata()?.bindings || {};
  const _dataSource = worksheet.getCustomMetadata()?.dataSource || {};

  if (!_bindings.hasOwnProperty(dataPath)) {
    console.warn(`[removeBindingPath] 绑定路径不存在: ${dataPath}`);
    return;
  }

  // 删除绑定
  delete _bindings[dataPath];

  // 可选：同步删除 dataSource 中的值（你可根据业务决定是否保留）
  delete _dataSource[dataPath];

  // 更新元数据
  if (_customMetadata) {
    _customMetadata.bindings = { ..._bindings };
    _customMetadata.dataSource = { ..._dataSource };
    worksheet.setCustomMetadata(_customMetadata);
  }
  console.log(`[removeBindingPath] 已删除绑定: ${dataPath}`);
}

// 以下为vueUI页面操作
//单个绑定
function addSingleBinding() {
  if (!singlePath.value || !singleRange.value) return;
  bindings[singlePath.value] = singleRange.value;
  setBindingPath(singlePath.value, singleRange.value);
  singlePath.value = "";
  singleRange.value = "";
}

//批量绑定
function addBatchBinding() {
  try {
    const parsed = JSON.parse(batchJson.value);
    Object.assign(bindings, parsed);
    setBinding(parsed);
  } catch (e) {
    alert("JSON 格式错误");
  }
}
// 删除绑定
function removeBinding(path: string) {
  delete bindings[path];
  removeBindingPath(path);
}
// 开始编辑
function startEdit(path: string) {
  editing.value = {
    oldPath: path, // 旧 key（删除时用）
    path, // 当前 key（可能改动）
    range: bindings[path], // 当前 range
  };
}

// 保存修改
function saveEdit() {
  if (!editing.value) return;
  const { oldPath, path, range } = editing.value;

  // 若 key 有变化，先删除旧 key
  if (oldPath !== path) {
    delete bindings[oldPath];
    removeBindingPath(oldPath);
  }
  // 写入新值
  bindings[path] = range;
  setBindingPath?.(path, range);
  editing.value = null;
}

// 取消编辑
function cancelEdit() {
  editing.value = null;
}
// --- 数据源相关 ---
const dataSourceJson = ref("");
const currentDataSource = ref<string>("");

function setDataSourceFromInput() {
  try {
    const parsed = JSON.parse(dataSourceJson.value);
    setDataSource(parsed);
    console.log("数据源已更新并同步到所有绑定单元格");
  } catch (e) {
    alert("数据源 JSON 格式错误");
  }
}

function getDataSourceToSpan() {
  const ds = getDataSource();
  currentDataSource.value = ds ? JSON.stringify(ds, null, 2) : "暂无数据";
}
// 监听单元格选择变化
function onSelectionChanged(callback: (selections: any) => void): IDisposable {
  const dragManagerService = props.injector.get(SheetsSelectionsService);
  return toDisposable(
    dragManagerService.selectionChanged$
      .pipe(filter((cell) => !!cell))
      .subscribe((selections) => {
        callback(selections);
      })
  );
}
onSelectionChanged((params: any) => {
  if (params.length > 0) {
    const ref = sr(params[0].range);
    //console.log(ref);
    singleRange.value = ref;
  }
});

// 执行加载初始绑定和数据源，并监听单元格值变化
loadBindings();
</script>

<style scoped>
.binding-panel {
  padding: 20px;
  max-width: 800px;
  margin: auto;
  font-family: sans-serif;
}

.form-section {
  margin-bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

textarea,
input {
  padding: 3px;
  font-size: 14px;
}

button {
  width: fit-content;
}

.bindings table {
  width: 100%;
  min-width: 320px;
  /* 根据实际内容调整 */
  border-collapse: collapse;
  margin-top: 10px;
}

.bindings th,
.bindings td {
  border: 1px solid #ccc;
  padding: 4px;
  text-align: left;
  height: 40px;
  width: 30%;
}

.bindings th {
  background-color: #f2f2f2;
}

.bindings button {
  margin-right: 5px;
}

pre {
  background: #f6f8fa;
  padding: 8px;
  border: 1px solid #e1e4e8;
  border-radius: 4px;
  max-height: 200px;
  overflow: auto;
  font-size: 13px;
}
</style>
